﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
using OpenLS.Core;
using OpenLS.Drawing;
using Geometry = System.Windows.Media.Geometry;

namespace OpenLS.Spreadsheet.UI.Internals
{
    public static class TempDrawingHelper
    {
#if DEBUG
        private static readonly Brush testBrush = new SolidColorBrush(Color.FromArgb(15, 128, 128, 60));
        
#endif
        private static Geometry _commentGeometry;

        private static Geometry CommentGeometry
        {
            get
            {
                if (_commentGeometry == null)
                {
                    const double s = 6;
                    _commentGeometry =
                        new PathGeometry(
                            new List<PathFigure>
                                {
                                    new PathFigure(
                                        new Point(0, 0),
                                        new List<PathSegment>
                                            {
                                                new LineSegment(
                                                    new Point( 0, s),
                                                    false),
                                                new LineSegment(
                                                    new Point(  -s, 0),
                                                    false),
                                                new LineSegment(
                                                    new Point(  0, 0),
                                                    false)
                                            }
                                        ,
                                        true)
                                }
                            );
                }
                return _commentGeometry;
            }
        }


        private static void renderCommentTriangle(DrawingContext drawingContext,Point origin,  double width)
        {
            using (new TransformContext(drawingContext, new TranslateTransform(origin.X + width, origin.Y)))
            {
                drawingContext.DrawGeometry(Brushes.Red, null, CommentGeometry);
            }
        }

        private static Brush getBrush(SpreadsheetColor foreground, ColorScheme scheme, ColorMode mode)
        {
            switch (mode)
            {
                case ColorMode.BlackAndWhite:
                    return Brushes.Black;
                default:
                    {
                        return ColorToBrushConverter.GetBrush(foreground, scheme);
                    }
            }
        }


        internal static Rect RenderCell(DrawingContext drawingContext,
            CellArrangeInfo cellArrangeInfo, Func<Cell, CellTextRenderingInformation> provider,ColorMode mode, Func<Cell, Rect> rectFn)
        {
            Rect result = cellArrangeInfo.CellRect;
            try
            {
                if (cellArrangeInfo.CellHeight == 0)
                    return result;
                if (cellArrangeInfo.CellWidth == 0 && cellArrangeInfo.MaxBoundsWithOverflow.Width == 0)
                    return result;
#if DEBUG
                drawingContext.DrawRectangle(testBrush, null, cellArrangeInfo.CellRect);
#endif
                var cell = cellArrangeInfo.Cell;
                if (cell == null)
                    return result;
                if (cell.Value == null && cell.Comment == null)
                    return result;
                if (cell.ConditionalFormattings != null)
                {
                    foreach (var c in cell.ConditionalFormattings)
                    {
                        if (Enumerable.Any(Enumerable.OfType<DataBarFormattingRule>(c.Rules),
                                           r => !r.DataBar.ShowValue))
                            return result;
                    }
                }
                if (!cell.Column.IsVisible || !cell.Row.IsVisible)
                {
                    if (Enumerable.All(cell.GetColumns(), column => !column.IsVisible))
                        if (Enumerable.All(cell.GetRows(), row => !row.IsVisible))
                            return result;
                }
                CellTextRenderingInformation cellTextRenderingInformation = provider(cell);
                if (cell.Value is double && cell.Format is GeneralFormat)
                {
                    if (cell.Column.ActualCharacterWidth != cellTextRenderingInformation.lastColumnWidth)
                        cellTextRenderingInformation = provider(cell);
                }

                var origin = cellArrangeInfo.CellOrigin;
                TextWrapping cellTextWrapping = cell.TextWrapping;
                switch (cell.ActualHorizontalAlignment)
                {
                    case HorizontalCellAlignment.Left:
                        origin.Offset(2, 0);
                        origin.Offset(10*cell.Indentation, 0);
                        break;
                    case HorizontalCellAlignment.Center:
                        if (!cellTextRenderingInformation.IsSpecial)
                        {
                            if (cellTextWrapping == TextWrapping.NoWrap)
                                origin.Offset(cellArrangeInfo.CellWidth/2, 0);
                        }
                        break;
                    case HorizontalCellAlignment.CenterContinuous:
                        {
                            Func<Cell, bool> f =
                                c =>
                                c != null && c.Value == null &&
                                c.ActualHorizontalAlignment == HorizontalCellAlignment.CenterContinuous;
                            var rightMostCell = cell;
                            while (f(rightMostCell.GetNeighbor(NavigationDirection.Right)))
                                rightMostCell = rightMostCell.GetNeighbor(NavigationDirection.Right);
                            double width = +rectFn(rightMostCell).Right - origin.X;
                            if (cellTextWrapping == TextWrapping.NoWrap)
                                origin.Offset(width/2, 0);
                            break;
                        }
                    case HorizontalCellAlignment.Right:
                        if (!cellTextRenderingInformation.IsSpecial)
                        {
                            if (cellTextWrapping == TextWrapping.NoWrap)
                                origin.Offset(cellArrangeInfo.CellWidth, 0);
                        origin.Offset(-2, 0); //\\border
                        }                   
                break;
                }
                VerticalCellAlignment v = cell.VerticalAlignment;
                switch (v)
                {
                    case VerticalCellAlignment.Top:
                        //\\  case VerticalCellAlignment.Stretch:
                        break;
                    case VerticalCellAlignment.Center:
                        origin.Offset(0, Math.Max(0, cellArrangeInfo.CellHeight - cellTextRenderingInformation.TextHeight) / 2);
                        break;
                    case VerticalCellAlignment.Bottom:
                        origin.Offset(0, Math.Max(0, cellArrangeInfo.CellHeight - 2 - cellTextRenderingInformation.TextHeight));
                        break;
                    default:
                        break;
                        //\\throw new NotSupportedException();
                }
                RectangleGeometry clip = null;
                RectangleGeometry wrapClip = null;
                if (cellTextWrapping != TextWrapping.NoWrap)
                {
                    cellTextRenderingInformation.FormattedText.MaxTextWidth = cellArrangeInfo.CellWidth;
                    var maxTextHeight = Math.Max(cellArrangeInfo.CellHeight,
                                                 cellTextRenderingInformation.FormattedText.Height);
                    cellTextRenderingInformation.FormattedText.MaxTextHeight = maxTextHeight;
                    if (maxTextHeight < cellArrangeInfo.CellHeight)
                    {
                        wrapClip = new RectangleGeometry(new Rect(cellArrangeInfo.CellOrigin, new Size(cellArrangeInfo.CellWidth, cellArrangeInfo.CellHeight)));
                    }
                }
                else if (cell.CanOverflow)
                {
                    if (cellTextRenderingInformation.FormattedText.TextAlignment == TextAlignment.Right)
                        result = new Rect(origin.X - cellTextRenderingInformation.TotalTextWidth, cellArrangeInfo.CellOrigin.Y, cellTextRenderingInformation.TotalTextWidth, cellArrangeInfo.CellHeight);
                    else
                    result = new Rect(origin.X, cellArrangeInfo.CellOrigin.Y, cellTextRenderingInformation.TotalTextWidth, cellArrangeInfo.CellHeight);
                    if (cellArrangeInfo.NeedsClip(new Size(cellTextRenderingInformation.TotalTextWidth, cellTextRenderingInformation.TextHeight)))
                    {
                        double m = cellArrangeInfo.MaxBoundsWithOverflow.Width;
                        const double maxClipSize = 100000;
                        if (m > maxClipSize)
                            m = maxClipSize;
                        Rect r;
                        switch (cell.ActualHorizontalAlignment)
                        {
                            case HorizontalCellAlignment.Center:
                                case HorizontalCellAlignment.CenterContinuous:
                                r = new Rect(cellArrangeInfo.MaxBoundsWithOverflow.Min, cellArrangeInfo.CellOrigin.Y, Math.Min(cellArrangeInfo.MaxBoundsWithOverflow.Width, maxClipSize), cellArrangeInfo.CellHeight);
                                Contract.Assert(r.Width < 1000000000000);
                                break;
                            default:
                                r = new Rect(cellArrangeInfo.CellOrigin, new Size(m, cellArrangeInfo.CellHeight));
                                break;
                        }
                        clip = new RectangleGeometry(r);
                        Contract.Assert(clip.Bounds.Width < 1000000000000000);

                    }
                }
                else
                {
                    FormattedText t2 = null;
                    if (cellTextRenderingInformation.TotalTextWidth > cellArrangeInfo.CellWidth)
                    {
                        t2 =
                            new FormattedText("###############################################################",
                                              CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                                              cell.Typeface, cell.ActualFontSizeInPixel,
                                              getBrush(cell.ActualForeground,
                                                       cell.Worksheet.Workbook.ColorScheme, mode))
                                {TextAlignment = cell.TextAlignment};
                        clip = new RectangleGeometry(cellArrangeInfo.CellRect);
                        Contract.Assert(clip.Bounds.Width < 1000000000000000);

                    }
                    if (cellTextRenderingInformation.TextHeight > cellArrangeInfo.CellHeight && clip == null)
                    {
                        clip = new RectangleGeometry(cellArrangeInfo.CellRect);
                        Contract.Assert(clip.Bounds.Width < 1000000000000000);

                    }
                    if (t2 != null)
                    {
                        Contract.Assert(clip != null);
                        
                        drawingContext.PushClip(clip);
                        drawingContext.DrawText(t2, origin);
                        drawingContext.Pop();
                        return result;
                    }
                }
                //\\
               // clip = null;
                if (clip != null)
                {
                    Contract.Assert(clip.Bounds.Width < 1000000000000);
                    drawingContext.PushClip(clip);
                }
                if (wrapClip != null)
                {
                    drawingContext.PushClip(wrapClip);
                }
                if (cellTextRenderingInformation.Transform != null)
                {
                    drawingContext.PushTransform(cellTextRenderingInformation.Transform);
                }
                if (cellTextRenderingInformation.RightFormattedText != null)
                {
                    if (cellTextRenderingInformation.HasRepeatText)
                    {
                        FormattedText ft =
                            cellTextRenderingInformation.GetRepeatText(
                                cellArrangeInfo.CellWidth, new CellDisplayInfoKey(cell, mode),
                                mode);
                        if (ft != null)
                            drawingContext.DrawText(ft, origin);
                    }
                    else
                    {
                        drawingContext.DrawText(cellTextRenderingInformation.FormattedText, new Point(origin.X + 2, origin.Y));
                        drawingContext.DrawText(cellTextRenderingInformation.RightFormattedText,
                                                new Point(origin.X + cellArrangeInfo.CellWidth - 2, origin.Y));
                    }
                }
                else if (cellTextRenderingInformation.HasRepeatText)
                {
                    FormattedText ft = cellTextRenderingInformation.GetRepeatText(
                                                    cellArrangeInfo.CellWidth, new CellDisplayInfoKey(cell, mode),
                                                    mode);
                    if (ft != null)
                        drawingContext.DrawText(ft, origin);                    
                }
                else
                {
                    drawingContext.DrawText(cellTextRenderingInformation.FormattedText, origin);
                }
                if (cellTextRenderingInformation.Transform != null)
                {
                    drawingContext.Pop();
                }
                if (clip != null)
                {
                    drawingContext.Pop();
                }
                if (wrapClip != null)
                {
                    drawingContext.Pop();
                }
                if (cell.Comment != null)
                {
                    renderCommentTriangle(drawingContext, cellArrangeInfo.CellOrigin, cellArrangeInfo.CellWidth);
                }
                return result;
            }
            catch (Exception)
            {
                drawingContext.DrawText(
                    new FormattedText("INTERNAL ERROR", CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                                      new Typeface("Aial"), 12, Brushes.Pink), new Point(0, 0));
                return result;
            }
        }

    }
}